﻿#include <system/scene_system.h>
#include <gui/GuiBase.h>
#include <imgui_internal.h>
#include <Jolt/Jolt.h>
#include <Jolt/Physics/PhysicsSystem.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <Jolt/Core/JobSystem.h>
#include <Jolt/Core/Factory.h>
#include <Jolt/Core/JobSystemThreadPool.h>
#include <Jolt/RegisterTypes.h>
#include <physical/3d/layer_interface.h>
#include <physical/3d/temp_allocator.h>
#include <utl/entt.h>
#include <component/transform.h>
#include <utl/tree_node.h>
#include <utl/async.h>

namespace primal
{

	constexpr u32 m_max_body_count{ 10240u };
	constexpr u32 m_body_mutex_count{ 0u };
	constexpr u32 m_max_body_pairs{ 65536u };
	constexpr u32 m_max_contact_constraints{ 10240u };

	static const JPH::Vec3Arg m_gravity{ 0.f, 0.f, -9.8f };

	static struct
	{
		LayerInterfaceImpl layer_interface;
		PhysicalTempAllocator temp_allocator{ 16 * 1024 * 1024 };
		utl::unique_ptr<JPH::Factory> physical_factory;
		utl::unique_ptr<JPH::PhysicsSystem> physics_system;
		utl::unique_ptr<JPH::JobSystem> job_system;
		utl::registry entity_system;
		utl::tree_node<entt::entity> scene_tree;
		utl::sync_queue sync;
		bool is_init;
	}global{};

	static struct
	{
		utl::vector<entt::entity> root_scenes;
		entt::entity cur_entity{ entt::null };
	}ctx{};

	entt::entity create_entity(component::COM_TYPE types)
	{
		auto e = global.entity_system.create();
		if(types & component::COM_TYPE_TRANS)
		{
			global.entity_system.emplace<component::transform>(e);
		}
		if(types & component::COM_TYPE_GTRANS)
		{
			global.entity_system.emplace<component::global_transform>(e);
		}
		if(types & component::COM_TYPE_PROP)
		{
			global.entity_system.emplace<component::property_info>(e);
		}
		if(types & component::COM_TYPE_CAMERA)
		{
			global.entity_system.emplace<component::camera>(e);
		}
		if(types & component::COM_TYPE_LIGHT)
		{
			global.entity_system.emplace<component::light>(e);
		}
		return e;
	}

	using tree_iter = utl::tree_node<entt::entity>::node_ref;

	struct render_scene_tree_ctx
	{
		entt::entity right_click_entity{ entt::null };
	};

	void render_scene_tree(entt::entity par, render_scene_tree_ctx& out_ctx)
	{
		constexpr ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth;
		ImGuiTreeNodeFlags temp_flag = base_flags;
		auto& inf{ global.entity_system.get<component::property_info>(par) };
		if(ctx.cur_entity == par)
		{
			temp_flag |= ImGuiTreeNodeFlags_Selected;
		}

		bool tree_res{ false };
		ImGui::PushID(static_cast<int>(par));
		if(inf.child_count == 0u)
		{
			temp_flag |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
			ImGui::TreeNodeEx(inf.name, temp_flag);
		}
		else
		{
			tree_res = ImGui::TreeNodeEx(inf.name, temp_flag);
		}
		ImGui::PopID();

		//左键选择
		if((ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered(ImGuiHoveredFlags_None)))
		{
			ctx.cur_entity = par;
		}

		//右键菜单
		//constexpr std::string_view scene_menu_name{ "m1" };
		if((ImGui::IsMouseClicked(ImGuiMouseButton_Right) && ImGui::IsItemHovered(ImGuiHoveredFlags_None)))
		{
			out_ctx.right_click_entity = par;
		}

		if(tree_res)
		{
			for(u32 i{}; i < inf.child_count; ++i)
			{
				render_scene_tree(inf.child_entitys[i], out_ctx);
			}
			ImGui::TreePop();
		}
	}

	void add_entity(utl::sync_param& par)
	{
		entt::entity parent_entity = static_cast<entt::entity>(par.uiv[0]);
		auto e = create_entity(component::COM_TYPE_DEFAULT);
		auto& inf{ global.entity_system.get<component::property_info>(e) };
		auto& par_inf{ global.entity_system.get<component::property_info>(parent_entity) };
		par_inf.push_entity(e);
		inf.parent_entity = parent_entity;
		strcpy(inf.name, "child");
	}

	void ui_scene(const FontList& icon_ft, bool* life)
	{
		if(ImGui::Begin(u8"场景", life))
		{
			ImGui::Text("%.3f", ImGui::GetIO().Framerate);
			struct
			{
				bool is_add_scence_btn;
				bool is_add_scence;
			}var{};

			if(ImGui::Button(u8"添加场景"))
			{
				var.is_add_scence_btn = true;
			}

			static ImGuiEx::input_buffer scene_name_cache{};

			var.is_add_scence = ImGuiEx::InputWindow(u8"添加场景", scene_name_cache, var.is_add_scence_btn);

			if(var.is_add_scence)
			{
				auto e = create_entity(component::COM_TYPE_DEFAULT);
				auto& inf{ global.entity_system.get<component::property_info>(e) };
				strcpy(inf.name, scene_name_cache.data());
				scene_name_cache.fill(0);
				ctx.root_scenes.push_back(e);
				ctx.cur_entity = e;
			}

			for(auto item : ctx.root_scenes)
			{
				render_scene_tree_ctx tctx{};
				render_scene_tree(item, tctx);
				constexpr std::string_view scene_menu_name{ "m1" };
				static entt::entity valid_entity{};
				if(global.entity_system.valid(tctx.right_click_entity))
				{
					ImGui::OpenPopup(scene_menu_name.data());
					valid_entity = tctx.right_click_entity;
				}
				if(ImGui::BeginPopupContextVoid(scene_menu_name.data()))
				{
					if(ImGui::Selectable(u8"添加子实体"))
					{
						utl::sync_param param{};
						param.uiv[0] = static_cast<u32>(valid_entity);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
						global.sync.push(add_entity, param);
					}
					ImGui::EndPopup();
				}
			}
		}
		ImGui::End();
	}

	void ui_property(const FontList& icon_ft, bool* life)
	{

	}
}

#include <res/icon_font_def_u8.h>

bool primal::scene_initialize()
{
	if(global.is_init)
	{
		return global.is_init;
	}

	gui::register_window(primal::ui_scene, "fuck", iconft::e912);

	/*gui::register_window([](const FontList& icon_ft, bool* life)
	{
		if(ImGui::Begin(u8"场景", life))
		{
			const static std::string_view right_menu_name{ u8"rmn" };
			const static std::string_view add_new_item_title{ u8"实体名称" };

			struct
			{
				bool is_open_new_title;
				bool is_add_entity;
			}var{};

			if(ImGui::BeginPopupContextWindow())
			{
				if(ImGui::MenuItemEx(u8"创建实体", iconft::e928))
				{
					var.is_open_new_title = true;
				}
				ImGui::EndPopup();
			}

			static std::array<char, 256> title_buffer;

			var.is_add_entity = ImGuiEx::InputWindow(add_new_item_title.data(), title_buffer, var.is_open_new_title);

			if(var.is_add_entity)
			{
				auto entity_id = create_entity(component::COM_TYPE_DEFAULT);
				auto& prop = global.entity_system.get<component::property_info>(entity_id);
				strcpy(prop.name, title_buffer.data());
				title_buffer.fill(0);
			}

			auto view = global.entity_system.view<component::property_info>();

			for(auto entity : view)
			{
				auto& prop{ global.entity_system.get<component::property_info>(entity) };
				ImGui::Selectable(prop.name);
			}
		}
		ImGui::End();
	}, u8"场景", iconft::e912);*/



	{
		JPH::AlignedAllocate = phys::aligned_allocate_impl;
		JPH::Allocate = phys::allocate_impl;
		JPH::AlignedFree = phys::aligned_free_impl;
		JPH::Free = phys::free_impl;
		global.physical_factory = utl::make_unique<JPH::Factory>();
		JPH::Factory::sInstance = global.physical_factory.get();
		JPH::RegisterTypes();

		global.physics_system = utl::make_unique<JPH::PhysicsSystem>();
		global.job_system = utl::make_unique<JPH::JobSystemThreadPool>(1024u, 8u, 4);

		global.physics_system->Init
		(
			m_max_body_count,
			m_body_mutex_count,
			m_max_body_pairs,
			m_max_contact_constraints,
			global.layer_interface,
			JPH::ObjectVsBroadPhaseLayerFilter{},
			JPH::ObjectLayerPairFilter{}
		);

		global.physics_system->SetPhysicsSettings({});

		global.physics_system->SetGravity(m_gravity);

	}

	global.is_init = true;
	return global.is_init;
}

void primal::tick(float delta)
{
//	global.physics_system->Update(delta, 1, &global.temp_allocator, global.job_system.get());
	global.sync.do_thing();
}

void primal::shutdown()
{}
